package com.bluestone;

import java.io.Serializable;
import java.util.Map;

import com.bluestone.util.ValueStack;
import com.bluestone.ActionInvocation;

public class ActionContext implements Serializable{
	
	static ThreadLocal actionContext = new ThreadLocal();
	/**
     * Constant for the name of the action being executed.
     */
    public static final String ACTION_NAME = "com.bluestone.ActionContext.name";
    
    /**
     * Constant for the {@link com.bluestone.util.ValueStack OGNL value stack}.
     */
    public static final String VALUE_STACK = ValueStack.VALUE_STACK;
    
    /**
     * Constant for the action's project.
     */
    public static final String PROJECT = "com.bluestone.ActionContext.project";
    
    
    /**
     * Constant for the action's testsuite.
     */
    public static final String TESTSUITE = "com.bluestone.ActionContext.testsuite";
    
    
    /**
     * Constant for the action's testcase.
     */
    public static final String TESTCASE = "com.bluestone.ActionContext.testcase";
    
    /**
     * Constant for the action's command.
     */
    public static final String COMMAND = "com.bluestone.ActionContext.command";

    
    /**
     * Constant for the action's parameters.
     */
    public static final String PARAMETERS = "com.bluestone.ActionContext.parameters";
    
    /**
     * Constant for the action's {@link com.bluestone.ActionInvocation invocation} context.
     */
    public static final String ACTION_INVOCATION = "com.bluestone.ActionContext.actionInvocation";
    
    Map<String, Object> context;
    
    /**
     * Creates a new ActionContext initialized with another context.
     *
     * @param context a context map.
     */
    public ActionContext(Map<String, Object> context) {
        this.context = context;
    }
    
    /**
     * Sets the action invocation (the execution state).
     *
     * @param actionInvocation the action execution state.
     */
    public void setActionInvocation(ActionInvocation actionInvocation) {
        put(ACTION_INVOCATION, actionInvocation);
    }  
    
    /**
     * Gets the action invocation (the execution state).
     *
     * @return the action invocation (the execution state).
     */
    public ActionInvocation getActionInvocation() {
        return (ActionInvocation) get(ACTION_INVOCATION);
    }
    
    /**
     * Sets the action's project context.
     *
     * @param project the action's project context.
     */
    public void setProject(Map<String, Object> project) {
        put(PROJECT, project);
    }

    /**
     * Returns a Map of  a generic project level Map otherwise.
     *
     * @return a Map of generic project level Map
     */
    public Map<String, Object> getProject() {
        return (Map<String, Object>) get(PROJECT);
    }
    
    /**
     * Sets the action's testsuite context.
     *
     * @param testsuite the action's testsuite context.
     */
    public void setTestsuite(Map<String, Object> testsuite) {
        put(TESTSUITE, testsuite);
    }

    /**
     * Returns a Map of  a generic testsuite level Map otherwise.
     *
     * @return a Map of generic testsuite level Map
     */
    public Map<String, Object> getTestsuite() {
        return (Map<String, Object>) get(TESTSUITE);
    }   
    
    /**
     * Sets the action's testcase context.
     *
     * @param testsuite the action's testcase context.
     */
    public void setTestcase(Map<String, Object> testcase) {
        put(TESTCASE, testcase);
    }

    /**
     * Returns a Map of  a generic testcase level Map otherwise.
     *
     * @return a Map of generic testcase level Map
     */
    public Map<String, Object> getTestcase() {
        return (Map<String, Object>) get(TESTCASE);
    } 
    
    /**
     * Sets the action's command context.
     *
     * @param testsuite the action's command context.
     */
    public void setCommand(Map<String, Object> command) {
        put(COMMAND, command);
    }

    /**
     * Returns a Map of  a generic command level Map otherwise.
     *
     * @return a Map of generic command level Map
     */
    public Map<String, Object> getCommand() {
        return (Map<String, Object>) get(COMMAND);
    }     
    
    /**
     * Sets the action context for the current thread.
     *
     * @param context the action context.
     */
    public static void setContext(ActionContext context) {
        actionContext.set(context);
    }

    /**
     * Returns the ActionContext specific to the current thread.
     *
     * @return the ActionContext for the current thread, is never <tt>null</tt>.
     */
    public static ActionContext getContext() {
        return (ActionContext) actionContext.get();

        // Don't do lazy context creation, as it requires container; the creation of which may 
        // precede the context creation
        //if (context == null) {
        //    ValueStack vs = ValueStackFactory.getFactory().createValueStack();
        //    context = new ActionContext(vs.getContext());
        //    setContext(context);
        //}

    }
    
    /**
     * Sets the action's context map.
     *
     * @param contextMap the context map.
     */
    public void setContextMap(Map<String, Object> contextMap) {
        getContext().context = contextMap;
    }
    
    /**
     * Gets the context map.
     *
     * @return the context map.
     */
    public Map<String, Object> getContextMap() {
        return context;
    }
    
    /**
     * Sets the name of the current Action in the ActionContext.
     *
     * @param name the name of the current action.
     */
    public void setName(String name) {
        put(ACTION_NAME, name);
    }

    /**
     * Gets the name of the current Action.
     *
     * @return the name of the current action.
     */
    public String getName() {
        return (String) get(ACTION_NAME);
    }
    
    /**
     * Sets the action parameters.
     *
     * @param parameters the parameters for the current action.
     */
    public void setParameters(Map<String, Object> parameters) {
        put(PARAMETERS, parameters);
    }

    /**
     * Returns a Map of the HttpServletRequest parameters when in a servlet environment or a generic Map of
     * parameters otherwise.
     *
     * @return a Map of HttpServletRequest parameters or a multipart map when in a servlet environment, or a
     *         generic Map of parameters otherwise.
     */
    public Map<String, Object> getParameters() {
        return (Map<String, Object>) get(PARAMETERS);
    }    
    
    /**
     * Sets the OGNL value stack.
     *
     * @param stack the OGNL value stack.
     */
    public void setValueStack(ValueStack stack) {
        put(VALUE_STACK, stack);
    }

    /**
     * Gets the OGNL value stack.
     *
     * @return the OGNL value stack.
     */
    public ValueStack getValueStack() {
        return (ValueStack) get(VALUE_STACK);
    }    
    
    
    
    /**
     * Returns a value that is stored in the current ActionContext by doing a lookup using the value's key.
     *
     * @param key the key used to find the value.
     * @return the value that was found using the key or <tt>null</tt> if the key was not found.
     */
    public Object get(String key) {
        return context.get(key);
    }

    /**
     * Stores a value in the current ActionContext. The value can be looked up using the key.
     *
     * @param key   the key of the value.
     * @param value the value to be stored.
     */
    public void put(String key, Object value) {
        context.put(key, value);
    }    
    
	
}
